#ifndef _DELETEHANDLER_H_
#define _DELETEHANDLER_H_ 1

#include "Referenced.h"
#include <list>
#include "threading/mutex.h"

namespace FD
{
	namespace Kernel
	{
		/** Class for overriding the default delete behaviour so that users can implement their own object
		* deletion schemes.
		* This might be used to implement a protection scheme that avoids
		* multiple threads deleting objects unintentionally.
		* Note, the CDeleteHandler cannot itself be reference counted, otherwise it
		* would be responsible for deleting itself!
		* A static auto_ptr<> is used internally in CReferenced.cpp to manage the
		* CDeleteHandler's memory.*/
		class FD_Kernel_Export CDeleteHandler
		{
		public:

			typedef std::pair<unsigned int, const FD::Kernel::CReferenced*> FrameNumberObjectPair;
			typedef std::list<FrameNumberObjectPair> ObjectsToDeleteList;

			CDeleteHandler(int numberOfFramesToRetainObjects=0);

			virtual ~CDeleteHandler();

			/** Set the number of frames to retain objects that have been requested for deletion.
			* When set to zero objects are deleted immediately, by setting to 1 they are kept around for an extra frame etc.
			* The ability to retain objects for several frames is useful to prevent premature deletion when objects
			* are still being used by graphics threads that use double buffering of rendering data structures with
			* non ref_ptr<> pointers to scene graph elements.*/
			void setNumFramesToRetainObjects(unsigned int numberOfFramesToRetainObjects) {  _numFramesToRetainObjects = numberOfFramesToRetainObjects; }

			unsigned int getNumFramesToRetainObjects() const { return _numFramesToRetainObjects; }

			/** Set the current frame number so that subsequent deletes get tagged as associated with this frame.*/
			void setFrameNumber(unsigned int frameNumber) { _currentFrameNumber = frameNumber; }

			/** Get the current frame number.*/
			unsigned int getFrameNumber() const { return _currentFrameNumber; }

			inline void doDelete(const CReferenced* object) { delete object; }

			/** Flush objects that are ready to be fully deleted.*/
			virtual void flush();

			/** Flush all objects that the CDeleteHandler holds.
			* Note, this should only be called if there are no threads running with non ref_ptr<> pointers, such as graphics threads.*/
			virtual void flushAll();

			/** Request the deletion of an object.
			* Depending on users implementation of CDeleteHandler, the delete of the object may occur
			* straight away or be delayed until doDelete is called.
			* The default implementation does a delete straight away.*/
			virtual void requestDelete(const FD::Kernel::CReferenced* object);

		protected:

			CDeleteHandler(const CDeleteHandler&):
				 _numFramesToRetainObjects(0),
					 _currentFrameNumber(0) {}
				 CDeleteHandler operator = (const CDeleteHandler&) { return *this; }

				 unsigned int            _numFramesToRetainObjects;
				 unsigned int            _currentFrameNumber;
				 FD::Kernel::Mutex      _mutex;
				 ObjectsToDeleteList     _objectsToDelete;
		};
	}
}

#endif